﻿using DataModels.Models;
using GenericTools.CustomReporting;
using GenericTools.DataExporting;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace ReportingManagement.Components.Queries
{
    /// <summary>
    /// Interaction logic for QueryResults.xaml
    /// </summary>
    public partial class QueryResults : Window
    {
        #region Class Variables
        private Query theQuery = null;
        private ObservableCollection<Query> queries = new ObservableCollection<Query>();
        private Dictionary<string, string> previousQueryParameterValues = new Dictionary<string, string>();

        private DataTable currentQueryData = null;
        private BackgroundWorker backgroundWorker = null;
        private QueryExecutionStatus queryExecutionStatus = null;

        private DateTime startOfRunningQuery;
        private DispatcherTimer timer = null;
        #endregion

        #region Constructors
        public QueryResults()
        {
            InitializeComponent();

            queryExecutionStatus = new QueryExecutionStatus();
            dataGridQueryStatus.DataContext = queryExecutionStatus;

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = false;
            backgroundWorker.WorkerSupportsCancellation = false;
            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;

            timer = new DispatcherTimer();
            timer.Tick += timer_Tick;
            timer.Interval = new TimeSpan(0, 0, 1);
        }

        public QueryResults(Query queryToRun) : this()
        {
            this.Title = string.Format("Query Result - {0}", queryToRun.Name);
            this.theQuery = queryToRun;
            queries.Add(theQuery);
            cboReport.ItemsSource = queries;
            cboReport.SelectedItem = this.theQuery;
        }

        public QueryResults(QueryCategory category) : this()
        {
            this.Title = string.Format("Query Result - Category: {0}", category.Name);
            foreach (var item in category.Queries) queries.Add(item);
            cboReport.ItemsSource = queries;
        }

        public QueryResults(ICollection<Query> queries) : this()
        {
            this.Title = "Query Result";
            foreach (var item in queries) this.queries.Add(item);
            cboReport.ItemsSource = this.queries;
        }
        #endregion

        #region Event Handlers
        void timer_Tick(object sender, EventArgs e)
        {
            TimeSpan timeSpan = DateTime.Now - startOfRunningQuery;
            queryExecutionStatus.TimeTaken = string.Format("Time elapsed: {0:00}:{1:00}:{2:00}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);
        }

        void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            timer.Stop();
            timer_Tick(null, null);

            if (e.Error == null)
            {
                queryExecutionStatus.ExecutionStatus = QueryExecutionStatus.QUERY_SUCCESS_TEXT;
                DataTable dataTable = e.Result as DataTable;
                currentQueryData = dataTable;
                queryExecutionStatus.RowsReturned = string.Format("{0} rows", dataTable.Rows.Count);

                dataGridResults.ItemsSource = dataTable.DefaultView;
                btnExportToExcel.IsEnabled = dataTable.Rows.Count > 0;
                btnTransformToChart.IsEnabled = dataTable.Rows.Count > 0;
            }
            else
            {
                queryExecutionStatus.ExecutionStatus = QueryExecutionStatus.QUERY_ERROR_TEXT;
                string message = e.Error.Message;
                var soapException = e.Error as System.Web.Services.Protocols.SoapException;
                if (soapException != null)
                {
                    // We will assume for every SoapException there will stack trace as part of its message.
                    // But we don't want to display the trace, so We'll assume the message ends before the
                    // appearance of 'at System.' phrase
                    int targetIndex = soapException.Message.IndexOf("at System.");
                    if (targetIndex != -1) message = soapException.Message.Substring(0, targetIndex);
                    message = message.Trim();
                }

                MessageBox.Show(message, GenericTools.AppConfiguration.ApplicationName,
                                MessageBoxButton.OK, MessageBoxImage.Error);
            }

            btnRun.IsEnabled = true;
            cboReport.IsEnabled = true;
        }

        void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            object[] arguments = e.Argument as object[];
            Query query = (Query)arguments[0];
            List<string> parameterValues = (List<string>)arguments[1];

            DataTable dataTable = ReportQuerying.RunQuery(query, parameterValues);
            e.Result = dataTable;
        }

        private void btnRun_Click(object sender, RoutedEventArgs e)
        {
            Query query = cboReport.SelectedItem as Query;
            if (query != null)
            {
                List<string> parameterValues = new List<string>();
                if (query.QueryParameters.Count > 0)
                {
                    var parameterCollector = new ReportParameterCollector(query.QueryParameters, previousQueryParameterValues);
                    bool? okToContinue = parameterCollector.ShowDialog();
                    if (!okToContinue.HasValue) return;
                    if (okToContinue.HasValue && okToContinue.Value == false) return;
                    else
                    {
                        foreach (var param in query.QueryParameters)
                        {
                            string parameterValue = parameterCollector.ParameterValues
                                .Where(v => v.Name == param.Name)
                                .SingleOrDefault().Value;

                            parameterValues.Add(parameterValue);
                        }

                        // Here we are saving the parameter values, in case they pop up again
                        foreach (var param in parameterCollector.ParameterValues)
                        {
                            string key = param.Name;
                            previousQueryParameterValues[key] = param.Value;
                        }
                    }
                }

                btnRun.IsEnabled = false;
                cboReport.IsEnabled = false;                

                object[] arguments = new object[] { query, parameterValues };

                queryExecutionStatus.ExecutionStatus = QueryExecutionStatus.QUERYING_TEXT;
                startOfRunningQuery = DateTime.Now;
                timer.Start();
                backgroundWorker.RunWorkerAsync(arguments);
            }
        }

        private void btnExportToExcel_Click(object sender, RoutedEventArgs e)
        {
            if (currentQueryData != null)
            {
                try
                {
                    ExcelFileExporting excelExporter = new ExcelFileExporting(currentQueryData);
                    string outputFile = excelExporter.Export();
                    System.Diagnostics.Process.Start(outputFile);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, GenericTools.AppConfiguration.ApplicationName,
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }
        #endregion
    }
}
